package com.jadcon.bedbreakfast.domain;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
import org.springframework.security.authentication.encoding.Md5PasswordEncoder;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.provisioning.JdbcUserDetailsManager;
import org.springframework.stereotype.Component;

@Component("customerRepository")
public class CustomerRepositoryImpl implements CustomerRepository {

	@Autowired
	private PhoneRepository phoneRepository;

	@Autowired
	private JdbcUserDetailsManager jdbcUserDetailsManager;

	private SimpleJdbcTemplate simpleJdbcTemplate;
	
	@SuppressWarnings("unchecked")
	public List<Customer> getCustomerList() {
		String sql = "select * from customer";
		List<Customer> customerList = this.simpleJdbcTemplate.query(sql,
				new CustomerMapper());
		for (Customer customer : customerList) {
			List<PhoneNumber> phoneNumberList = phoneRepository
					.getAllPhoneNumbersByCustomerID(customer.getId());
			customer.setPhoneNumberList(phoneNumberList);
		}
		return customerList;
	}

	@SuppressWarnings("unchecked")
	public List<Customer> findByID(int id) {

		String sql = "select * from customer where id=?";
		List<Customer> customerList = this.simpleJdbcTemplate.query(sql,
				new CustomerMapper(), id);
		for (Customer customer : customerList) {
			List<PhoneNumber> phoneNumberList = phoneRepository
					.getAllPhoneNumbersByCustomerID(customer.getId());
			customer.setPhoneNumberList(phoneNumberList);
		}
		return customerList;
	}

	@SuppressWarnings("unchecked")
	public List<Customer> findByName(String name) {

		String sql = "select * from customer where name=?";
		List<Customer> customerList = this.simpleJdbcTemplate.query(sql,
				new CustomerMapper(), name);
		for (Customer customer : customerList) {
			List<PhoneNumber> phoneNumberList = phoneRepository
					.getAllPhoneNumbersByCustomerID(customer.getId());
			customer.setPhoneNumberList(phoneNumberList);
		}
		return customerList;
	}

	@SuppressWarnings("unchecked")
	public Customer findByUsername(String username) {
		String sql = "select * from customer where username=?";
		List<Customer> customerList = this.simpleJdbcTemplate.query(sql,
				new CustomerMapper(), username);
		int customerListSize = customerList.size();
		if (customerListSize == 1) {
			Customer customer = customerList.get(0);
			List<PhoneNumber> phoneNumberList = phoneRepository
					.getAllPhoneNumbersByCustomerID(customer.getId());
			customer.setPhoneNumberList(phoneNumberList);
			return customer;
		} else if (customerListSize > 1) {
			throw new RuntimeException("expected 1, but found "
					+ customerListSize
					+ " customer objects found for username " + username);
		}
		return null;
	}

	public void save(Customer customer) {
		if (customer.getId() == 0) {
			insert(customer);
		} else {
			update(customer);
		}
	}

	private void insert(Customer unsavedCustomer) {

		String sql = "insert into customer (username, password, name, name2, address1, address2, city, state, zip, email) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
		simpleJdbcTemplate.update(sql, unsavedCustomer.getUsername(), unsavedCustomer.getPassword(), unsavedCustomer.getName(), unsavedCustomer.getName2(),
				unsavedCustomer.getAddress1(), unsavedCustomer.getAddress2(),
				unsavedCustomer.getCity(), unsavedCustomer.getState(),
				unsavedCustomer.getZip(), unsavedCustomer.getEmail());
		
		// insert username and password into USER
		String encryptedPassword = new Md5PasswordEncoder().encodePassword(unsavedCustomer.getPassword(), null);
		User user = new User(unsavedCustomer.getUsername(), encryptedPassword, true, true, true, true, new ArrayList<GrantedAuthority>());
		jdbcUserDetailsManager.createUser(user);
		jdbcUserDetailsManager.addUserToGroup(user.getUsername(), "GROUP_USER");
		
		// get the id from the newly saved customer
		Customer customer = findByUsername(unsavedCustomer.getUsername());
		int id = customer.getId();

		List<PhoneNumber> phoneList = unsavedCustomer.getPhoneNumberList();
		for (PhoneNumber phoneNumber : phoneList) {
			phoneRepository.save(phoneNumber, id);
		}
	}

	private void update(Customer customer) {
		String sql = "update customer set name=?, name2=?, address1=?, address2=?, city=?, state=?, zip=?, email=?, password=? where id=?";
		simpleJdbcTemplate.update(sql, customer.getName(), customer.getName2(), customer.getAddress1(),
				customer.getAddress2(), customer.getCity(),
				customer.getState(), customer.getZip(), customer.getEmail(), customer.getPassword(), customer.getId());

		// insert username and password into USER
		String encryptedPassword = new Md5PasswordEncoder().encodePassword(customer.getPassword(), null);
		String username = customer.getUsername();
		String userSql = "update users set password=? where username=?";
		simpleJdbcTemplate.update(userSql, encryptedPassword, username);
		
		
		List<PhoneNumber> phoneList = customer.getPhoneNumberList();
		int customerId = customer.getId();
		for (PhoneNumber phoneNumber : phoneList) {
			phoneRepository.save(phoneNumber, customerId);
		}
	}

	public void delete(int id) {
		
		List<Customer> customerList = findByID(id);
		Customer customer = customerList.get(0);
		String username = customer.getUsername();
		
		String sql = "delete from customer where id=?";
		simpleJdbcTemplate.update(sql, id);
		
		String sql2 = "delete from users where username=?";
		simpleJdbcTemplate.update(sql2, username);
		
		String sql3 = "delete from group_members where username=?";
		simpleJdbcTemplate.update(sql3, username);
		
		String sql4 = "delete from phone where customer_id=?";
		simpleJdbcTemplate.update(sql4, id);
		
	}
	
	@SuppressWarnings("unchecked")
	public List<State> getStateList(){
		String sql = "Select * from state ORDER BY name ASC";
		return simpleJdbcTemplate.query(sql, new StateMapper());
	}

	@SuppressWarnings("unchecked")
	private static final class CustomerMapper implements RowMapper {

		public Customer mapRow(ResultSet rs, int rowNum) throws SQLException {
			int id = rs.getInt("id");
			String username = rs.getString("username");
			String password = rs.getString("password");
			String name = rs.getString("name");
			String name2 = rs.getString("name2");
			String address1 = rs.getString("address1");
			String address2 = rs.getString("address2");
			String city = rs.getString("city");
			String state = rs.getString("state");
			int zip = rs.getInt("zip");
			String email = rs.getString("email");

			Customer customer = new Customer(id, username, password, name,
					name2, address1, address2, city, state, zip, email);

			return customer;
		}
	}

	@SuppressWarnings("unchecked")
	public static final class StateMapper implements RowMapper {

		public State mapRow(ResultSet rs, int rowNum) throws SQLException {
			int id = rs.getInt("id");
			String name = rs.getString("name");
			String abbreviation = rs.getString("abbreviation");
			State state = new State(id, name, abbreviation);
			return state;
		}
	}

	@Autowired
	public void setDataSource(DataSource dataSource) {
		simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
	}


}
